﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using Microsoft.SqlServer.Dts.Pipeline;
using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
using Microsoft.SqlServer.Dts.Pipeline.Design;
using Microsoft.SqlServer.Dts.Runtime;
using Microsoft.SqlServer.Dts.Design;

namespace Pestre.SqlServer.SSIS.DataFlowComponent
{
    /*
     * This form represents the "Edit" window of ErrorOutputDescription component.
     * The class is instanciated when user click the "Edit" on the component.
     * 
     * It allows user to view and change the component properties.
     */
    public partial class ErrorOutputDescriptionUIForm90 : Form
    {
        // Component MetaData
        IDTSComponentMetaData90 _md;
        // Column Information of the component
        VirtualInputColumns90 _VirtualInputColumns;

        /*
         * Instantiate the form and initialize all textboxes with the 
         * component properties.
         */
        public ErrorOutputDescriptionUIForm90(IDTSComponentMetaData90 md)
        {
            StartPosition = FormStartPosition.CenterScreen;
            _md = md;
            _VirtualInputColumns = new VirtualInputColumns90(md);

            // Call base methode
            InitializeComponent();
            // Initialize the first tab with user's preferences
            InitializeComponent_ConfigurationTab();
            // Initialize the second tab with Input and Output columns
            InitializeComponent_InputOutputTab();
            // Initialize the third tab with Lineage data
            InitializeComponent_LineageTab();
        }

        /*
         * Initialize some checkboxes with component's custom properties.
         *     - Checkbox 1 : Add Error Description or not
         *     - Checkbox 2 : Add Component Name or not
         *     - Checkbox 3 : Add Column Name or not
         *     - Checkbox 4 : Add Column Type or not
         *     - Checkbox 5 : Add Column Length or not
         */
        private void InitializeComponent_ConfigurationTab()
        {
            cbErrorCode.Checked   = (bool)_md.CustomPropertyCollection[ErrorOutputDescription.PROP_ERROR_CODE].Value;
            cbErrorColumn.Checked = (bool)_md.CustomPropertyCollection[ErrorOutputDescription.PROP_ERROR_COLUMN].Value;
            cbDescription.Checked = (bool)_md.CustomPropertyCollection[ErrorOutputDescription.PROP_ERROR_DESCRIPTION].Value;
            cbComponent.Checked   = (bool)_md.CustomPropertyCollection[ErrorOutputDescription.PROP_COMPONENT_NAME].Value;
            cbName.Checked        = (bool)_md.CustomPropertyCollection[ErrorOutputDescription.PROP_COLUMN_NAME].Value;
            cbType.Checked        = (bool)_md.CustomPropertyCollection[ErrorOutputDescription.PROP_COLUMN_TYPE].Value;
            cbLength.Checked      = (bool)_md.CustomPropertyCollection[ErrorOutputDescription.PROP_COLUMN_LENGTH].Value;
        }

        /*
         * Initialize a datagrid with all available input and their usage from
         * the component's custom properties.
         * 
         * The user can choose to redirect these input to the Output Buffer or not.
         */
        private void InitializeComponent_InputOutputTab()
        {
            foreach (VirtualInputColumn90 vicColumn in _VirtualInputColumns.Collection)
            {
                Object[] sRow = new Object[6];

                sRow[0] = vicColumn.OutputColumn_IsUsed;
                sRow[1] = vicColumn.InputColumn_Name;
                sRow[2] = vicColumn.OutputColumn_Name;
                sRow[3] = vicColumn.InputColumn_UpstreamComponentName;
                sRow[4] = vicColumn.Input_ID;
                sRow[5] = vicColumn.InputColumn_LineageID;
                dataInputOutput.Rows.Add(sRow);
            }
        }

        /*
         * Initialize a datagrid with all column information available in the dataflow.
         * These data are readonly.
         * These data will be used during Running Time in order to generate Error Description.
         */
        private void InitializeComponent_LineageTab()
        {
            IDTSCustomProperty90 cpLineage = _md.CustomPropertyCollection[ErrorOutputDescription.PROP_LINEAGE_ID];

            // Retrieve and format all columns information from our custom property (Lineage ID)
            try
            {
                String   strLineage = (String)cpLineage.Value;
                String[] tabLineage = strLineage.Split(';');

                for (int i = 0; i < tabLineage.Length - 1; i++)
                {
                    String[] tabDetail = tabLineage[i].Split(':');
                    dataLineage.Rows.Add(tabDetail);
                }
            }
            catch (Exception)
            {
                bool bCancel;
                _md.FireError(0, _md.Name, "Bad '" + ErrorOutputDescription.PROP_LINEAGE_ID + "' property.", "", 0, out bCancel);
            }
        }

        /*
         * If user click the Cancel button or press "Echap" the window is closed and no modification
         * will be applied to the component's properties. (Exception for Lineage Information).
         */
        private void btnCancel_Click(object sender, EventArgs e)
        {
            this.DialogResult = DialogResult.Cancel;
            this.Close();
        }

        /*
         * If user click the OK button or press "Enter" the window is closed and all modification
         * will be applied to the component's properties.
         */
        private void btnOK_Click(object sender, EventArgs e)
        {
            try
            {
                // Throw exception if duplicate names are used
                CheckUniqueName();

                // Save Configuration Tab choice
                _md.CustomPropertyCollection[ErrorOutputDescription.PROP_ERROR_CODE].Value = cbErrorCode.Checked;
                _md.CustomPropertyCollection[ErrorOutputDescription.PROP_ERROR_COLUMN].Value = cbErrorColumn.Checked;
                _md.CustomPropertyCollection[ErrorOutputDescription.PROP_ERROR_DESCRIPTION].Value = cbDescription.Checked;
                _md.CustomPropertyCollection[ErrorOutputDescription.PROP_COMPONENT_NAME].Value = cbComponent.Checked;
                _md.CustomPropertyCollection[ErrorOutputDescription.PROP_COLUMN_NAME].Value = cbName.Checked;
                _md.CustomPropertyCollection[ErrorOutputDescription.PROP_COLUMN_TYPE].Value = cbType.Checked;
                _md.CustomPropertyCollection[ErrorOutputDescription.PROP_COLUMN_LENGTH].Value = cbLength.Checked;

                // Create output collection depending on user choice
                _md.OutputCollection[0].OutputColumnCollection.RemoveAll();
                _VirtualInputColumns.SetAllUnused();
                if (cbErrorCode.Checked)
                {
                    IDTSOutputColumn90 outErrorCode = _md.OutputCollection[0].OutputColumnCollection.New();
                    outErrorCode.Name = ErrorOutputDescription.EOD_ERROR_CODE;
                    outErrorCode.SetDataTypeProperties(Microsoft.SqlServer.Dts.Runtime.Wrapper.DataType.DT_I4, 0, 0, 0, 0);
                }
                if (cbErrorColumn.Checked)
                {
                    IDTSOutputColumn90 outErrorColumn = _md.OutputCollection[0].OutputColumnCollection.New();
                    outErrorColumn.Name = ErrorOutputDescription.EOD_ERROR_COLUMN;
                    outErrorColumn.SetDataTypeProperties(Microsoft.SqlServer.Dts.Runtime.Wrapper.DataType.DT_I4, 0, 0, 0, 0);
                }
                if (cbDescription.Checked)
                {
                    IDTSOutputColumn90 outDescription = _md.OutputCollection[0].OutputColumnCollection.New();
                    outDescription.Name = ErrorOutputDescription.EOD_ERROR_DESCRIPTION;
                    outDescription.SetDataTypeProperties(Microsoft.SqlServer.Dts.Runtime.Wrapper.DataType.DT_STR, 500, 0, 0, 1252);
                }
                if (cbComponent.Checked)
                {
                    IDTSOutputColumn90 outComponent = _md.OutputCollection[0].OutputColumnCollection.New();
                    outComponent.Name = ErrorOutputDescription.EOD_COMPONENT_NAME;
                    outComponent.SetDataTypeProperties(Microsoft.SqlServer.Dts.Runtime.Wrapper.DataType.DT_STR, 100, 0, 0, 1252);
                }
                if (cbName.Checked)
                {
                    IDTSOutputColumn90 outName = _md.OutputCollection[0].OutputColumnCollection.New();
                    outName.Name = ErrorOutputDescription.EOD_COLUMN_NAME;
                    outName.SetDataTypeProperties(Microsoft.SqlServer.Dts.Runtime.Wrapper.DataType.DT_STR, 100, 0, 0, 1252);
                }
                if (cbType.Checked)
                {
                    IDTSOutputColumn90 outType = _md.OutputCollection[0].OutputColumnCollection.New();
                    outType.Name = ErrorOutputDescription.EOD_COLUMN_TYPE;
                    outType.SetDataTypeProperties(Microsoft.SqlServer.Dts.Runtime.Wrapper.DataType.DT_STR, 100, 0, 0, 1252);
                }
                if (cbLength.Checked)
                {
                    IDTSOutputColumn90 outLength = _md.OutputCollection[0].OutputColumnCollection.New();
                    outLength.Name = ErrorOutputDescription.EOD_COLUMN_LENGTH;
                    outLength.SetDataTypeProperties(Microsoft.SqlServer.Dts.Runtime.Wrapper.DataType.DT_I4, 0, 0, 0, 0);
                }

                // Create output columns to redirect input columns choosed by user
                foreach (DataGridViewRow row in dataInputOutput.Rows)
                {
                    if (row.IsNewRow)
                        continue;

                    bool IsUsed = (bool)row.Cells[0].Value;
                    if (IsUsed == false)
                        continue;

                    int inputID = (int)row.Cells[4].Value;
                    int LineageID = (int)row.Cells[5].Value;
                    foreach (VirtualInputColumn90 vicColumn in _VirtualInputColumns.Collection)
                        if (vicColumn.Input_ID == inputID && vicColumn.InputColumn_LineageID == LineageID)
                        {
                            // Create and save output column
                            IDTSOutputColumn90 outCol = _md.OutputCollection[0].OutputColumnCollection.New();
                            outCol.Name = (String)row.Cells[2].Value;
                            outCol.SetDataTypeProperties((Microsoft.SqlServer.Dts.Runtime.Wrapper.DataType)vicColumn.DataType, vicColumn.Length, vicColumn.Precision, vicColumn.Scale, vicColumn.CodePage);
                            vicColumn.AttachOutput(outCol);
                            break;
                        }
                }
                _VirtualInputColumns.Save(); // Store information in custom properties

                // If everything went ok, the window is closed
                this.DialogResult = DialogResult.OK;
                txtInfo.Visible = false;
                txtInfo.Text = "";
                this.Close();
            }
            catch (Exception ex)
            {
                // If an error occured, the window is not closed and a message is displayed.
                txtInfo.Text = ex.Message;
                txtInfo.Visible = true;
                txtInfo.Select(0, 0);
                tabctrlErrorDescription.SelectTab(tabConfiguration);
            }
        }

        /*
         * In the second tab, user can choose a name for the input columns redirected to output.
         * If two or more output columns have the same name, this method will throw an exception.
         */
        private void CheckUniqueName()
        {
            foreach (DataGridViewRow row in dataInputOutput.Rows)
            {
                if (row.IsNewRow)
                    continue;
                bool IsUsed = (bool)row.Cells[0].Value;
                if (IsUsed == false)
                    continue;

                int  inputID   = (int)row.Cells[4].Value;
                int  LineageID = (int)row.Cells[5].Value;
                String sAlias = (String)row.Cells[2].Value;

                // Check duplicates with reserved names
                if (sAlias.Equals(ErrorOutputDescription.EOD_ERROR_CODE)
                 || sAlias.Equals(ErrorOutputDescription.EOD_ERROR_COLUMN)
                 || sAlias.Equals(ErrorOutputDescription.EOD_ERROR_DESCRIPTION)
                 || sAlias.Equals(ErrorOutputDescription.EOD_COMPONENT_NAME)
                 || sAlias.Equals(ErrorOutputDescription.EOD_COLUMN_NAME)
                 || sAlias.Equals(ErrorOutputDescription.EOD_COLUMN_TYPE)
                 || sAlias.Equals(ErrorOutputDescription.EOD_COLUMN_LENGTH))
                    throw new ApplicationException(sAlias + " is a reserved name, choose a different Alias.");

                // Check duplicates within all inputs
                foreach (DataGridViewRow row2 in dataInputOutput.Rows)
                {
                    if (row2.IsNewRow)
                        continue;
                    bool IsUsed2 = (bool)row2.Cells[0].Value;
                    if (IsUsed2 == false)
                        continue;

                    int inputID2 = (int)row2.Cells[4].Value;
                    int LineageID2 = (int)row2.Cells[5].Value;
                    String sAlias2 = (String)row2.Cells[2].Value;
                    if (inputID != inputID2 || LineageID != LineageID2)
                        if (sAlias.Equals(sAlias2))
                            throw new ApplicationException("Duplicate name '" + sAlias + "', choose a different Alias.");
                }
            }
        }
    }
}
